//
//  MLoaddingHudToast.swift
//  ToastTest
//
//  Created by huangweiqiang on 2022/6/13.
//

/**
 
 用例：
 
 self.view.showLoaddingHUD(message: "正在登录", hudType: .labActivity_v)
 
 self.view.showHUDWithImage(message: "问题是非中断长文本导致在问题是非中断长文本导1", image: UIImage.init(named: "Bwol")!)
 
 self.view.showLoaddingHUD(message: nil, postion: .top)
 
 self.view.handleLoaddingHUD()
 
 */


import Foundation
import UIKit
let ml_screenWidth: CGFloat = UIScreen.main.bounds.size.width
let ml_screenHeight: CGFloat = UIScreen.main.bounds.size.height

enum MLoaddingHudToastType {
    case toast
    case activity  //只有activity
    case labActivity_h  //label+activity
    case labActivity_v  //label+activity
    case imgLabel_h  //图片(左) + label（右）
    case imgLabel_v  //图片（上） + label （下）
}

enum MLPositionType {
    case top
    case center
    case bottom
}


struct MLoaddingHudConfig {
    var paddingLeft: CGFloat = 15
    var paddingRight: CGFloat = 15
    var paddingTop: CGFloat = 10
    var paddingBottom: CGFloat = 10
    var space: CGFloat = 6
    var lineSpace: CGFloat = 2
    var img_width: CGFloat = 68
    var img_height: CGFloat = 68
    var max_width: CGFloat = ml_screenWidth * 0.75
    var toast_duration: CGFloat = 2 //时长
    var loaddingW: CGFloat = 82
    init() {
        //
    }
}

var ml_toastView_key : UnsafePointer<UIView>?    =   nil
var ml_config: MLoaddingHudConfig = MLoaddingHudConfig()
var ml_toast_time_key: UnsafePointer<Timer>? = nil


extension UIView {
    ///底部的安全间隙是31 而不是34
    class func topPadding() -> CGFloat {
        var topHeight: CGFloat = 0
        if #available(iOS 13.0, *) {
            let statusBarManager = UIApplication.shared.windows.first?.safeAreaInsets
            topHeight = statusBarManager?.top ?? 0
        }else{
            if #available(iOS 11.0, *) {
                topHeight = UIApplication.shared.keyWindow?.safeAreaInsets.top ?? 0
            } else {
                topHeight = 0
            }
        }
        return topHeight
    }
    
    ///底部的安全间隙是31 而不是34
    class func bottomPadding() -> CGFloat{
        var bottomHeight: CGFloat = 0
        if #available(iOS 13.0, *) {
            let statusBarManager = UIApplication.shared.windows.first?.safeAreaInsets
            bottomHeight = statusBarManager?.bottom ?? 0
        }else{
            if #available(iOS 11.0, *) {
                bottomHeight = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
            } else {
                bottomHeight = 0
            }
        }
        return bottomHeight
    }
    
    ///获取Loadding内容视图
    fileprivate func ml_LoaddingHudView(message: String? = nil,
                                        image: UIImage? = nil,
                                        hudType: MLoaddingHudToastType? = .activity,
                                        postion: MLPositionType? = .center) -> UIView {
        var tempView = objc_getAssociatedObject(self, &ml_toastView_key) as? UIView
        if tempView == nil {
            tempView = self.createHudContentView(message: message,image: image, hudType: hudType)
            objc_setAssociatedObject(self, &ml_toastView_key, tempView!, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        return tempView!
    }
    
    ///创建内容视图
    fileprivate func createHudContentView(message: String? = nil,
                                          image: UIImage? = nil,
                                          hudType: MLoaddingHudToastType? = .activity) -> UIView {
        let tempView = UIView.init(frame: CGRect.zero)
        tempView.backgroundColor = UIColor.init(hex: 0x333333, alpha: 1)
        tempView.layer.cornerRadius = 4
        tempView.layer.masksToBounds = true
        
        let stackView = self.createHudContentStackView(message: message, image: image, hudType: hudType)
        tempView.addSubview(stackView)
//        stackView.layer.borderWidth = 1
//        stackView.layer.borderColor = UIColor.red.cgColor
        tempView.frame.size = CGSize.init(width: stackView.frame.size.width + ml_config.paddingLeft + ml_config.paddingRight,
                                          height: stackView.frame.size.height + ml_config.paddingTop + ml_config.paddingBottom)
        stackView.frame.origin = CGPoint.init(x: ml_config.paddingLeft, y: ml_config.paddingTop)
        return tempView
    }
    
    ///装载视图
    fileprivate func createHudContentStackView(message: String? = nil, image: UIImage? = nil, hudType: MLoaddingHudToastType? = .activity) -> UIView {
        let tempStackView = UIStackView.init(frame: .zero)
        tempStackView.distribution = .fillProportionally
        tempStackView.axis = .horizontal
        tempStackView.spacing = ml_config.space
        tempStackView.alignment = .center
        tempStackView.backgroundColor = .clear
        
        switch hudType {
        case .toast:
            let titleLab = self.createTitleLabel(message: message)
            tempStackView.addArrangedSubview(titleLab)
            tempStackView.frame.size.width = max(titleLab.frame.size.width, ml_config.loaddingW)
            tempStackView.frame.size.height = max(titleLab.frame.size.height, 20)
        case .activity:
            tempStackView.distribution = .fill
            tempStackView.spacing = 0
            tempStackView.axis = .vertical
            tempStackView.alignment = .center
            
            let aView = self.createActivityView()
            tempStackView.addArrangedSubview(aView)
            
            tempStackView.frame.size = CGSize.init(width: ml_config.loaddingW, height: ml_config.loaddingW)
            aView.snp.makeConstraints { make in
                make.centerX.equalTo(tempStackView.frame.size.width/2)
                make.centerY.equalTo(tempStackView.frame.size.width/2)
            }
        case .labActivity_h:
            let titleLab = self.createTitleLabel(message: message)
            let activityView = self.createActivityView()
            tempStackView.axis = .horizontal
            tempStackView.addArrangedSubview(activityView)
            tempStackView.addArrangedSubview(titleLab)
            tempStackView.frame.size.width = titleLab.frame.size.width + activityView.frame.size.width + ml_config.space
            tempStackView.frame.size.height = max(titleLab.frame.size.height, activityView.frame.size.height, 20)
        case .labActivity_v:
            tempStackView.axis = .vertical
            let titleLab = self.createTitleLabel(message: message)
            let activityView = self.createActivityView()
            tempStackView.addArrangedSubview(activityView)
            tempStackView.addArrangedSubview(titleLab)
            tempStackView.frame.size.width = max(titleLab.frame.size.width, ml_config.loaddingW)
            tempStackView.frame.size.height = max(titleLab.frame.size.height + activityView.frame.size.height + ml_config.space, ml_config.loaddingW)
        case .imgLabel_v:
            tempStackView.axis = .vertical
            let titleLab = self.createTitleLabel(message: message)
            let imgView = self.createImgView(image: image)
            imgView.snp.makeConstraints { make in
                make.size.equalTo(CGSize.init(width: ml_config.img_width, height: ml_config.img_height))
            }
            
            tempStackView.addArrangedSubview(imgView)
            tempStackView.addArrangedSubview(titleLab)
            tempStackView.frame.size.width = max(titleLab.frame.size.width, ml_config.loaddingW)
            tempStackView.frame.size.height = max(titleLab.frame.size.height + imgView.frame.size.height + ml_config.space, ml_config.loaddingW)
        case .imgLabel_h:
            tempStackView.axis = .horizontal
            let titleLab = self.createTitleLabel(message: message)
            let imgView = self.createImgView(image: image)
            let cons_w = NSLayoutConstraint.init(item: imgView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 0, constant: ml_config.img_width)
            let cons_h = NSLayoutConstraint.init(item: imgView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 0, constant: ml_config.img_height)
            imgView.addConstraints([cons_w, cons_h])
            
            tempStackView.addArrangedSubview(imgView)
            tempStackView.addArrangedSubview(titleLab)
            
            tempStackView.frame.size.width = titleLab.frame.size.width + imgView.frame.size.width + ml_config.space
            tempStackView.frame.size.height = max(titleLab.frame.size.height, imgView.frame.size.height, 20)
        default:
            ()
        }
        tempStackView.layoutIfNeeded()
        return tempStackView
    }
    
    fileprivate func createTitleLabel(message: String? = nil) -> UILabel {
        let titleLab = UILabel.init(frame: CGRect.init(x: 0, y: 0, width: 2000, height: 10000))
        titleLab.textColor = UIColor.white
        titleLab.font = UIFont.systemFont(ofSize: 14)
        titleLab.backgroundColor = UIColor.clear
        titleLab.textAlignment = .center
        titleLab.numberOfLines = 1
        titleLab.lineBreakMode = .byWordWrapping
        titleLab.text = message
        titleLab.sizeToFit()
        
        if titleLab.frame.size.width > ml_config.max_width {
            //多行的情况下
            let attr = NSMutableAttributedString.init(string: message ?? "")
            var attrDict:[NSAttributedString.Key : Any] = [:]
            let paraStyle = NSMutableParagraphStyle()
            paraStyle.lineSpacing = ml_config.lineSpace
            attrDict[NSAttributedString.Key.paragraphStyle] = paraStyle
            attrDict[NSAttributedString.Key.font] = UIFont.systemFont(ofSize:14)
            attr.addAttributes(attrDict, range: NSRange.init(location: 0, length: attr.length))
            titleLab.text = ""
            titleLab.attributedText = attr
            titleLab.textAlignment = .center
            titleLab.numberOfLines = 0
            titleLab.frame.size.width = ml_config.max_width
            let rect = titleLab.sizeThatFits(CGSize.init(width: ml_config.max_width,
                                                         height: ml_screenHeight/2))
            titleLab.frame = CGRect.init(x: 0, y: 0, width: rect.width, height: max(rect.height, 24))
        }else{
            //单行情况下
            titleLab.frame = CGRect.init(x: 0, y: 0, width: titleLab.frame.size.width, height: max(titleLab.frame.size.height, 24))
        }
        return titleLab
    }
    
    fileprivate func createActivityView() -> UIActivityIndicatorView {
        let activityView = UIActivityIndicatorView.init(activityIndicatorStyle: .whiteLarge)
        
        activityView.frame = CGRect.init(x: 0, y: 0, width: 20, height: 20)
        activityView.color = .white
        activityView.backgroundColor = UIColor.clear
        activityView.startAnimating()
        return activityView
    }
    
    fileprivate func createImgView(image: UIImage? = nil) -> UIImageView {
        if image == nil {
            return UIImageView.init(frame: .zero)
        }
        let tempImgView = UIImageView.init(frame: CGRect.init(x: 0, y: 0, width: ml_config.img_width, height: ml_config.img_height))
        tempImgView.backgroundColor = UIColor.clear
        tempImgView.image = image
        tempImgView.contentMode = .scaleAspectFit
        tempImgView.clipsToBounds = true
        return tempImgView
    }
    
    ///toast bottom提示（用了 HRToast+UIView）
    private  func makeToastInBottom(message: String,
                           duration: CGFloat? = 2) {
        self.makeToast(message: message, duration: duration, postion: .bottom)
    }
    
    ///toast提示 ( 用 HRToast+UIView )
  private func makeToast(message: String,
                   duration: CGFloat? = 2,
                   postion: MLPositionType? = .center) {
        
        let timer = objc_getAssociatedObject(self, &ml_toast_time_key) as? Timer
        if timer != nil {
            timer?.invalidate()
        }
        let exitToast = objc_getAssociatedObject(self, &ml_toastView_key) as? UIView
        if exitToast != nil {
            dismissToast(toast: exitToast!, durationFlag: false)
        }
        
        let tempHudView = self.ml_LoaddingHudView(message: message, hudType: .toast)
        switch postion {
        case .top:
            tempHudView.center = CGPoint.init(x: ml_screenWidth/2, y: UIView.topPadding() + 20 + tempHudView.frame.size.height/2)
        case .center:
            tempHudView.center = CGPoint.init(x: ml_screenWidth/2, y: ml_screenHeight/2)
        case .bottom:
            tempHudView.center = CGPoint.init(x: ml_screenWidth/2, y: ml_screenHeight - tempHudView.frame.size.height/2 - UIView.bottomPadding() - 20)
        default:
            ()
        }
        self.addSubview(tempHudView)
        objc_setAssociatedObject(self, &ml_toastView_key, tempHudView, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        
        UIView.animate(withDuration: 0.24, delay: 0, options: .curveEaseInOut) {
            tempHudView.alpha = 1
        } completion: { flag in
            let timer = Timer.scheduledTimer(timeInterval: ml_config.toast_duration, target: self, selector: #selector(UIView.toastTimerDidFinish(timer:)), userInfo: tempHudView, repeats: false)
            objc_setAssociatedObject(self, &ml_toast_time_key, timer, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    ///定时器结速
    @objc func toastTimerDidFinish(timer: Timer) {
        dismissToast(toast: timer.userInfo as! UIView, durationFlag: true)
    }
    
    ///消失toast
    fileprivate func dismissToast(toast: UIView, durationFlag: Bool)  {
        if durationFlag {
            UIView.animate(withDuration: 0.24, delay: 0, options: .curveEaseInOut) {
                toast.alpha = 0
            } completion: { flag in
                if flag {
                    toast.removeFromSuperview()
                }
            }
        }else{
            toast.removeFromSuperview()
        }
    }
    
    
    ///展示LoaddingHUD
    func showLoadingHUDText(_ message: String? = nil,
                         hudType: MLoaddingHudToastType? = nil,
                         postion: MLPositionType? = .center) {
        var tempView = objc_getAssociatedObject(self, &ml_toastView_key) as? UIView
        if tempView == nil {
            var tempHudType = hudType
            if message ?? "" != "" {
                if hudType == nil || hudType == .activity || hudType == .toast || hudType == .imgLabel_v || hudType == .imgLabel_h {
                    tempHudType = .labActivity_h
                }
            }else{
                tempHudType = .activity
            }
            tempView = self.ml_LoaddingHudView(message: message, hudType: tempHudType, postion: postion)
        }
        
        self.addSubview(tempView!)
        objc_setAssociatedObject(self, &ml_toastView_key, tempView!, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        
        switch postion {
        case .top:
            tempView?.center = CGPoint.init(x: ml_screenWidth/2, y: ml_screenHeight/6)
        case .center:
            tempView?.center = CGPoint.init(x: ml_screenWidth/2, y: ml_screenHeight/2)
        case .bottom:
            tempView?.center = CGPoint.init(x: ml_screenWidth/2, y: ml_screenHeight*4/5)
        default:
            ()
        }
        
        UIView.animate(withDuration: 0.24, delay: 0, options: AnimationOptions.curveLinear) {
            tempView?.alpha = 1
        } completion: { flag in
            //
        }
    }
    
    ///自定义image+hud
    func showHUDWithImage(message: String? = nil,
                          image: UIImage,
                          hudType: MLoaddingHudToastType? = .imgLabel_v,
                          position: MLPositionType? = .center) {
        
        var tempView = objc_getAssociatedObject(self, &ml_toastView_key) as? UIView
        if tempView == nil {
            var tempHudType = hudType
            if hudType == nil || hudType == .activity || hudType == .toast || hudType == .labActivity_h || hudType == .labActivity_v {
                tempHudType = .imgLabel_v
            }
            tempView = self.ml_LoaddingHudView(message: message,
                                               image: image,
                                               hudType: tempHudType)
        }
        self.addSubview(tempView!)
        objc_setAssociatedObject(self, &ml_toastView_key, tempView!, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        
        tempView?.center = CGPoint.init(x: ml_screenWidth/2, y: ml_screenHeight/2)
        UIView.animate(withDuration: 0.24, delay: 0, options: AnimationOptions.curveLinear) {
            tempView?.alpha = 1
        } completion: { flag in
            //
        }
    }
    
    ///取消LoaddingHUD
    func handleLoading() {
        let tempView = objc_getAssociatedObject(self, &ml_toastView_key) as? UIView
        if tempView != nil {
            tempView?.removeFromSuperview()
        }
    }
}
